from enum import Enum
from dataclasses import dataclass
from copy import deepcopy
import numpy as np

from my_logging import GetLogger

logger = GetLogger('move')

class Direction(Enum):
    X = 0
    Y = 1


@dataclass
class CoordIndex():
    LEFT_UP : int
    LEFT_DOWN : int
    RIGHT_UP : int
    RIGHT_DOWN : int


class Move():
    """
    Takes the dict like:
    {
        "car_index": 0,
        "old": {
            "x": 1,
            "y": 2
        },
        "new": {
            "x": 6,
            "y": 2
        }
    }
    """

    CAR_INDEX_KEY_NAME = 'car_index'
    OLD_COORD_KEY_NAME = 'old'
    NEW_COORD_KEY_NAME = 'new'
    X_KEY_NAME = 'x'
    Y_KEY_NAME = 'y'

    def __init__(self, move_dict : dict) -> None:
        old_coord : tuple[int] = (
            move_dict[self.OLD_COORD_KEY_NAME][self.X_KEY_NAME], move_dict[self.OLD_COORD_KEY_NAME][self.Y_KEY_NAME]
        )
        new_coord : tuple[int] = (
            move_dict[self.NEW_COORD_KEY_NAME][self.X_KEY_NAME], move_dict[self.NEW_COORD_KEY_NAME][self.Y_KEY_NAME]
        )

        self.car_index : int = move_dict[self.CAR_INDEX_KEY_NAME]
        self.diff = np.array(new_coord) - np.array(old_coord)
        self.old = np.array(old_coord)
        self.new = np.array(new_coord)

        self.move_direction = Direction.X if np.nonzero(self.diff)[0][0] == 0 else Direction.Y


class MoveList():
    """
        move_dict_list takes a list of dict like:
        [
            {
                "car_index": 2,
                "old": {
                    "x": 1,
                    "y": 3
                },
                "new": {
                    "x": 3,
                    "y": 3
                }
            },
            ...
        ]
        """

    def __init__(self, move_dict_list : list[dict]) -> None:
        self.move_list : list[Move] = []
        for move_dict in move_dict_list:
            self.move_list.append(Move(move_dict))
        logger.debug(f'Length of move_dict_list = {len(move_dict_list)}')
        logger.debug(f'After init move list length = {len(self.move_list)}')


    def __getitem__(self, index : int) -> Move:
        return self.move_list[index]


    def Verify(self) -> bool:
        prev_move = self.move_list[0]
        for curr_move in self.move_list[1:]:
            if prev_move.car_index != curr_move.car_index:
                prev_move = curr_move
                continue

            if np.any(prev_move.new != curr_move.old):
                logger.debug(f'prev_move.new = {prev_move.new}, curr_move.old = {curr_move.old}')
                for m in self.move_list:
                    logger.debug(f'move car[{m.car_index}] {m.old} -> {m.new}')
                return False

            prev_move = curr_move

        return True


    def CalculateCompressedSteps(self) -> int:
        compressed_move_list : list[Move] = []
        for move in self.move_list:
            if not compressed_move_list:
                compressed_move_list.append(deepcopy(move))
                continue

            last_move = compressed_move_list[-1]
            if move.car_index == last_move.car_index:
                last_move.diff += move.diff
                continue

            compressed_move_list.append(deepcopy(move))

        void_move_list = []
        for move in compressed_move_list:
            if np.all(move.diff == np.array([0, 0])):
                void_move_list.append(move)

        for void_move in void_move_list:
            compressed_move_list.remove(void_move)

        return len(compressed_move_list)
